package com.zhiyun.notifier.client;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.net.NetUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONUtil;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import cn.hutool.system.SystemUtil;
import cn.hutool.system.UserInfo;
import com.zhiyun.notifier.constant.ApplicationEvent;
import com.zhiyun.notifier.entity.*;
import com.zhiyun.notifier.entity.type.HideAvatarType;
import com.zhiyun.notifier.props.DingProperties;
import org.springframework.beans.factory.annotation.Autowired;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URLEncoder;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 钉钉机器人客户端
 *
 * @author kun
 * @version 1.0.0
 */
public class DingTalkRobotClient {

    private static final Log log = LogFactory.get();

    @Autowired
    private DingProperties dingProperties;

    /**
     * 默认不验证签名
     * @param robotUrl
     * @return
     */
    public String getWebHook(String robotUrl) {
        return getWebHook(robotUrl,null,false);
    }

    /**
     * 计算签名
     * 参考：https://ding-doc.dingtalk.com/doc#/serverapi2/qf2nxq/9e91d73c
     *
     * @param secret    密钥，机器人安全设置页面，加签一栏下面显示的SEC开头的字符
     * @param timestamp 当前时间戳，毫秒级单位
     * @return 根据时间戳计算后的签名信息
     */
    private static String getSign(String secret, Long timestamp) {
        try {
            String stringToSign = timestamp + "\n" + secret;
            Mac mac = Mac.getInstance("HmacSHA256");
            mac.init(new SecretKeySpec(secret.getBytes("UTF-8"), "HmacSHA256"));
            byte[] signData = mac.doFinal(stringToSign.getBytes("UTF-8"));
            String sign = URLEncoder.encode(new String(Base64.encode(signData)), "UTF-8");
            log.debug("【发送钉钉群消息】获取到签名sign = {}", sign);
            return sign;
        } catch (Exception e) {
            log.error("【发送钉钉群消息】计算签名异常，errMsg = {}", e);
            return null;
        }
    }

    /**
     * 支持外部传入WebHook地址的方式发送消息
     *
     * @param url
     * @param message
     * @return
     */
    public DingTalkResponse sendMessageByURL(String url, BaseMessage message) {
        URI actualUrl;
        try {
            actualUrl = new URI(url);
        } catch (URISyntaxException e) {
            throw new RuntimeException("URL创建报错！");
        }
        return sendMessageByURL(actualUrl, message);
    }

    /**
     * 支持外部传入WebHook地址的方式发送消息
     *
     * @param url
     * @param message
     * @return
     */
    public DingTalkResponse sendMessageByURL(URI url, BaseMessage message) {
        String post = HttpUtil.post(url.toString(), JSONUtil.toJsonStr(message.toMessageMap()));
        System.out.println("结果："+post);
//        HttpHeaders headers = new HttpHeaders();
//        headers.setContentType(MediaType.APPLICATION_JSON);
//        HttpEntity<Map> entity = new HttpEntity<>(message.toMessageMap(), headers);
//        DingTalkResponse dingTalkResponse;
//
//        try {
//            dingTalkResponse =
//                    restTemplate.postForObject(url, entity, DingTalkResponse.class);
//        } catch (Exception e) {
//            log.error(e.fillInStackTrace().toString());
//            throw new DingTalkException(ResponseCodeType.UNKNOWN.getValue(), e.fillInStackTrace().toString());
//        }
//
//        // 对DingTalkResponse为空情况做异常封装
//        if (dingTalkResponse == null) {
//            throw new DingTalkException(ResponseCodeType.UNKNOWN.getValue(), "请求钉钉报错！");
//        }
//        if (!ResponseCodeType.OK.getValue().equals(dingTalkResponse.getErrcode())) {
//            throw new DingTalkException(dingTalkResponse.getErrcode(), dingTalkResponse.getErrmsg());
//        }
//        return dingTalkResponse;
        return null;
    }

    /**
     * 获取钉钉响应
     * @param robotUrl
     * @param message
     * @return
     */
    public DingTalkResponse sendMessageByAccessToken(String robotUrl, BaseMessage message) {
        return this.sendMessageByURL(getWebHook(robotUrl), message);
    }

    /**
     * 发送WebHook消息到钉钉
     *
     * @param message
     * @return
     */
    public DingTalkResponse sendMessage(BaseMessage message) {
        return this.sendMessageByURL(getWebHook(dingProperties.getRobotUrl()), message);
    }

    /**
     * 发送文本消息到钉钉
     *
     * @param message
     * @return
     */
    public DingTalkResponse sendTextMessage(TextMessage message) {
        return this.sendMessage(message);
    }

    /**
     * 发送文本消息到钉钉
     *
     * @param content
     * @return
     */
    public DingTalkResponse sendTextMessage(String content) {
        return this.sendMessage(new TextMessage(content));
    }

    /**
     * 发送文本消息到钉钉
     *
     * @param content
     * @param atMobiles
     * @return
     */
    public DingTalkResponse sendTextMessage(String content, String[] atMobiles) {
        return this.sendMessage(new TextMessage(content, atMobiles));
    }

    /**
     * 发送文本消息到钉钉
     *
     * @param content
     * @param isAtAll
     * @return
     */
    public DingTalkResponse sendTextMessage(String content, boolean isAtAll) {
        return this.sendMessage(new TextMessage(content, isAtAll));
    }

    /**
     * 发送Link消息到钉钉
     *
     * @param message
     * @return
     */
    public DingTalkResponse sendLinkMessage(LinkMessage message) {
        return this.sendMessage(message);
    }

    /**
     * 发送Link消息到钉钉
     *
     * @param title
     * @param text
     * @param messageUrl
     * @return
     */
    public DingTalkResponse sendLinkMessage(String title, String text, String messageUrl) {
        return this.sendMessage(new LinkMessage(title, text, messageUrl));
    }

    /**
     * 发送Link消息到钉钉
     *
     * @param title
     * @param text
     * @param messageUrl
     * @param picUrl
     * @return
     */
    public DingTalkResponse sendLinkMessage(String title, String text, String messageUrl, String picUrl) {
        return this.sendMessage(new LinkMessage(title, text, messageUrl, picUrl));
    }

    /**
     * 发送MarkDown消息到钉钉
     *
     * @param message
     * @return
     */
    public DingTalkResponse sendMarkdownMessage(MarkdownMessage message) {
        return this.sendMessage(message);
    }

    /**
     * 发送MarkDown消息到钉钉
     *
     * @param title
     * @param text
     * @return
     */
    public DingTalkResponse sendMarkdownMessage(String title, String text) {
        return this.sendMessage(new MarkdownMessage(title, text));
    }

    /**
     * 发送MarkDown消息到钉钉
     *
     * @param title
     * @param text
     * @param atMobiles
     * @return
     */
    public DingTalkResponse sendMarkdownMessage(String title, String text, String[] atMobiles) {
        return this.sendMessage(new MarkdownMessage(title, text, atMobiles));
    }

    /**
     * 发送MarkDown消息到钉钉
     *
     * @param title
     * @param text
     * @param isAtAll
     * @return
     */
    public DingTalkResponse sendMarkdownMessage(String title, String text, boolean isAtAll) {
        return this.sendMessage(new MarkdownMessage(title, text, isAtAll));
    }

    /**
     * 发送ActionCard消息到钉钉
     *
     * @param message
     * @return
     */
    public DingTalkResponse sendActionCardMessage(ActionCardMessage message) {
        return this.sendMessage(message);
    }

    /**
     * 发送ActionCard消息到钉钉
     *
     * @param title
     * @param text
     * @return
     */
    public DingTalkResponse sendActionCardMessage(String title, String text) {
        return this.sendMessage(new ActionCardMessage(title, text));
    }

    /**
     * 发送ActionCard消息到钉钉
     *
     * @param title
     * @param text
     * @param hideAvatar
     * @return
     */
    public DingTalkResponse sendActionCardMessage(String title, String text, HideAvatarType hideAvatar) {
        return this.sendMessage(new ActionCardMessage(title, text, hideAvatar));
    }

    /**
     * 发送ActionCard消息到钉钉
     *
     * @param title
     * @param text
     * @param button
     * @return
     */
    public DingTalkResponse sendActionCardMessage(String title, String text, ActionCardButton button) {
        return this.sendMessage(new ActionCardMessage(title, text, button));
    }

    /**
     * 发送ActionCard消息到钉钉
     *
     * @param title
     * @param text
     * @param hideAvatar
     * @param button
     * @return
     */
    public DingTalkResponse sendActionCardMessage(String title, String text, HideAvatarType hideAvatar, ActionCardButton button) {
        return this.sendMessage(new ActionCardMessage(title, text, hideAvatar, button));
    }

    /**
     * 发送FeedCard消息到钉钉
     *
     * @param feedCardMessage
     * @return
     */
    public DingTalkResponse sendFeedCardMessage(FeedCardMessage feedCardMessage) {
        return this.sendMessage(feedCardMessage);
    }

    /**
     * 发送FeedCard消息到钉钉
     *
     * @param feedCardItems
     * @return
     */
    public DingTalkResponse sendFeedCardMessage(List<FeedCardMessageItem> feedCardItems) {
        return this.sendMessage(new FeedCardMessage(feedCardItems));
    }

    /**
     * 拼接WebHook
     * @param robotUrl 从钉钉机器人中拷贝出来的webhook
     * @param secretToken
     * @param secretEnable 是否要加密签名 如果需要 则在webhook中添加根据secretToken生成的签名
     * @return
     */
    public String getWebHook(String robotUrl, String secretToken, boolean secretEnable) {
        //若启用加签加上时间戳跟签名串
        if (secretEnable) {
            Long timestamp = System.currentTimeMillis();
            robotUrl += "&timestamp=" + timestamp
                    + "&sign=" + getSign(secretToken, timestamp);
        }
        log.debug("The url contains sign is {}", robotUrl);
        return robotUrl;
    }

    /**
     * 默认不加密
     * @param robotUrl
     * @param secretToken
     * @return
     */
    public String getWebHook(String robotUrl, String secretToken) {
        return getWebHook(robotUrl, secretToken, false);
    }

    public void sendAppEventMessage(ApplicationEvent applicationEvent) {
        LinkedHashSet<String> localIps = NetUtil.localIps();
        String ips = localIps.stream().filter(s -> isIp(s) && !s.equals("127.0.0.1")).collect(Collectors.joining(","));
        UserInfo userInfo = SystemUtil.getUserInfo();
        StringBuilder sb = new StringBuilder();
        sb.append(dingProperties.getKeyword()).append("\n");
        switch (applicationEvent){
            case UP:
                boolean upNotifier = dingProperties.isUpNotifier();
                if(!upNotifier) return;
                sb.append("事件 : 服务上线😀\n");
                break;
            case DOWN:
                boolean downNotifier = dingProperties.isDownNotifier();
                if(!downNotifier) return;
                sb.append("事件 : 服务下线😭\n");
                break;
        }
        sb.append("环境 : ").append(dingProperties.getEnv()).append("\n");
        sb.append("项目 : ").append(dingProperties.getApplicationName()).append("\n");
        sb.append("时间 : ").append(DateUtil.now()).append("\n");
        sb.append("用户名 : ").append(userInfo.getName()).append("\n");
        sb.append("本机IP : ").append(ips);
        TextMessage textMessage = new TextMessage();
        textMessage.setContent(sb.toString());
        String mobiles = dingProperties.getMobiles();
        if(mobiles != null){
            textMessage.setAtMobiles(mobiles.split(","));
        }
        textMessage.setIsAtAll(false);
        textMessage.setContent(sb.toString());
        sendTextMessage(textMessage);
    }


    private boolean isIp(String ip) {
        return ip.matches("([1-9]|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])(\\.(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])){3}");
    }
}